package com.luych.toolbox.data.service.core.mysql;

import com.luych.toolbox.common.enums.CaseType;
import com.luych.toolbox.common.enums.DataSourceType;
import com.luych.toolbox.data.service.core.CoreBuilder;
import com.luych.toolbox.data.service.core.CoreColumn;
import com.luych.toolbox.data.service.core.CoreTable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

public class MysqlTable implements CoreTable {

    private final String name;
    private final String comment;
    private final List<MysqlColumn> columns;
    private final String primaryKeyName;
    private final List<String> primaryKey;

    public MysqlTable(CoreTable coreTable) {
        this.name = coreTable.getName();
        this.comment = coreTable.getComment();
        this.columns = coreTable.getColumns().stream()
                .map(column -> (MysqlColumn) CoreBuilder.buildColumn(DataSourceType.MYSQL, column))
                .collect(Collectors.toList());
        this.primaryKeyName = coreTable.getPrimaryKeyName();
        this.primaryKey = coreTable.getPrimaryKey();
    }

    public MysqlTable(String name, String comment, List<MysqlColumn> columns, String primaryKeyName, List<String> primaryKey) {
        this.name = name;
        this.comment = comment;
        this.columns = columns;
        this.primaryKeyName = primaryKeyName;
        this.primaryKey = primaryKey;
    }

    @Override
    public DataSourceType getDataSourceType() {
        return DataSourceType.MYSQL;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getComment() {
        return comment;
    }

    @Override
    public List<MysqlColumn> getColumns() {
        return columns;
    }

    @Override
    public String getPrimaryKeyName() {
        return primaryKeyName;
    }

    @Override
    public List<String> getPrimaryKey() {
        return primaryKey;
    }

    @Override
    public String getPageSql(CaseType caseType, long pageSize, long pageNo) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "`" + tableName + "`";
        return "SELECT * FROM " + tableName + " LIMIT " + (pageNo - 1) * pageSize + ", " + pageSize + ";";
    }

    @Override
    public String getSelectSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "`" + tableName + "`";
        return "SELECT * FROM " + tableName + ";";
    }

    @Override
    public String getCountSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "`" + tableName + "`";
        return "SELECT COUNT(*) FROM " + tableName + ";";
    }

    @Override
    public String getTruncateSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "`" + tableName + "`";
        return "TRUNCATE TABLE " + tableName + ";";
    }

    @Override
    public String getInsertSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "`" + tableName + "`";
        String columns = this.getColumns().stream().map(CoreColumn::getName).sorted().map(caseType.getConvert())
                .map(columnName -> "`" + columnName + "`").collect(Collectors.joining(","));
        String values = this.getColumns().stream().map(c -> "?").collect(Collectors.joining(","));
        return "INSERT INTO " + tableName + "(" + columns + ") VALUES (" + values + ")";
    }

    @Override
    public String getCreateSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());

        tableName = "`" + tableName + "`";

        String sql = "CREATE TABLE " + tableName + "(";
        StringJoiner joiner = new StringJoiner(",\n", "\n", "\n");
        for (MysqlColumn column : this.getColumns()) {
            String columnName = caseType.getConvert().apply(column.getName());
            columnName = "`" + columnName + "`";

            String joinerSql = "    " + columnName + " " + column.getColumnType();
            if (column.isIncrement()) {
                joinerSql += " AUTO_INCREMENT";
            }
            if (column.isNullable()) {
                joinerSql += " NULL";
            } else {
                joinerSql += " NOT NULL";
            }
            if (!StringUtils.isEmpty(column.getComment())) {
                joinerSql += " COMMENT '" + column.getComment() + "'";
            }
            joiner.add(joinerSql);
        }
        if (!CollectionUtils.isEmpty(this.getPrimaryKey())) {
            joiner.add("    PRIMARY KEY (" + caseType.getConvert().apply(String.join(",", this.getPrimaryKey())) + ")");
        }
        sql += joiner + ")";
        if (!StringUtils.isEmpty(this.getComment())) {
            sql += " COMMENT '" + this.getComment() + "'";
        }
        sql += ";";

        return sql;
    }

    @Override
    public String getCommentSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "`" + tableName + "`";
        return "ALTER TABLE " + tableName + " COMMENT '" + this.getComment() + "';";
    }

    @Override
    public String getRemoveSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "`" + tableName + "`";
        return "DROP TABLE " + tableName + ";";
    }

    @Override
    public String getCreatePrimaryKeySql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        String primaryKeyName = tableName + "_pk";

        tableName = "`" + tableName + "`";
        primaryKeyName = "`" + primaryKeyName + "`";

        return  "ALTER TABLE " + tableName +" " +
                "ADD CONSTRAINT " + primaryKeyName + " " +
                "PRIMARY KEY (" + caseType.getConvert().apply(String.join(",", this.getPrimaryKey())) + ");";
    }

    @Override
    public String getRemovePrimaryKeySql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "`" + tableName + "`";
        return "ALTER TABLE " + tableName + " DROP PRIMARY KEY;";
    }
}
